#include "ruleEngine.h"
#include <iostream>
#include <map>
#include <dlfcn.h>
#include <stdio.h>
#include <unistd.h>
#include "normaliser.hpp"
#include <string>
#include <client/dbclient.h>
#include <unistd.h>
unsigned int BUF_SIZE=1024;
/** \var char *str
    \brief Command to retrieve all files with extension .so*/
char *command_str="ls *.so";
/** \var map<string,maker_t *> factory
    \brief Factory map to store the object creator function of all the loaded libraries*/
map<string,maker_t *> factory;
map<string,maker_t *>::iterator fitr;
/** \var list<void *> dl_list
    \brief List to store the handles of loaded libraries */
list<void *> dl_list;
list<void *>::iterator itr;
/** \var list<string> norm_list
    \brief List to store the unique identifiers of loaded libraries*/
list<string> norm_list;
list<string>::iterator nitr;
/** \fn void open_libs(void)
    \brief Load all the libraries present in the current directory
    * Precondition: Uses the command "ls *.so" which must be valid.
    * Postcondition: The present libraries will be loaded with their and handlers in #dl_list
    \param void
    \return void */
void open_libs()
{
    char in_buf[BUF_SIZE];
    FILE *dl=popen(command_str,"r");
    if(!dl)
    {
        perror("popen");
        exit(-1);
    }
    void *dlib;
    char name[1024],i;
    while(fgets(in_buf,BUF_SIZE,dl))
    {
        char *ws=strpbrk(in_buf," \t\n");
        if(ws) *ws='\0';
        sprintf(name,"./%s",in_buf);
        dlib=dlopen(name,RTLD_NOW);
        if(dlib==NULL)
        {
            cerr<<dlerror()<<endl;
            exit(-1);
        }
        dl_list.insert(dl_list.end(),dlib);
    }
}
/** \fn void close_libs(void)
    \brief Close all the loaded libraries
    * Precondition: To be used at the time of exit
    * Postcondition: The loaded libraries are closed
    \param void
    \return void */

void close_libs()
{
    for(itr=dl_list.begin();itr!=dl_list.end();itr++)
    {
        dlclose(*itr);
    }
}
/** \fn void load_identifiers(void) 
    \brief Load the unique identifiers for loaded libraries
    * Precondition: To be used after open_libs()
    * Postcondition: identifiers loaded in #norm_list
    \param void
    \return void*/
void load_identifiers()
{
    for(fitr=factory.begin();fitr!=factory.end();fitr++)
    {
        norm_list.insert(norm_list.end(),fitr->first);
    }
}
/** \fn string get_idmatch(string )
    \brief Find the unique identifiers that matches in the log string
    * Precondition: All identifiers all loaded in #norm_list
    \param input The log string
    \return Value of the matched identifier */

string get_idmatch(string input)
{
    list<string>::iterator nitrl;
    size_t found;
    string rs="";
    for(nitrl=norm_list.begin();nitrl!=norm_list.end();nitrl++)
    {
        found=input.find(*nitrl);
        if(found!=string::npos)
        {
            rs=*nitrl;
            return rs;
        }
    }
    return rs;
}
/** \fn string getLog(long long int )
    \brief Fetch a log from test.logs based upon the ndex value
    \param index integer value for retrieving log
    \return String value of the message*/
string getLog(long long int index)
{
    using namespace mongo;
    using namespace std;
    DBClientConnection c;
    c.connect("localhost");
    auto_ptr<DBClientCursor> cursor=c.query("test.log",QUERY("index"<<index));
    if(cursor->more())
    {
        BSONObj doc=cursor->next();
        return doc["log"].str();
    }
    else
    {
        return "";
    }
}
/** \fn int main()
    \brief The starting point
    \param void
    \return int */
int main()
{
    using namespace std;
    /*Prepare the normaliser*/  
	open_libs();
    load_identifiers();
    /*Intialize the CLIPS environment*/
	ruleEngine r=ruleEngine("rules.clp");
    /** \var long long int n
        \brief Starting index value */
    long long int n=1;
    /*Loop for a maximum of 99999 index values*/
    while(n<99999)
    {
        /*Fetch the log*/
        string input=getLog(n);
        /*Empty value means the lig index does not exists*/
        if(input=="")
        {
            sleep(10);
            continue;
        }
        else
        {
            cout<<"INPUT:"<<input<<endl;    
	        /*Check if the log contains a valid identifier for normalisation */
            string id=get_idmatch(input);
            /*If no identifier is returned wait continue to next iteration*/
            if(id=="")
            continue;

            /*Create the Object from required library according to the identifier*/
            normaliser *obj=factory[id]();
            /*All objects contain the same normalise() function which returns a BSONObj*/
            mongo::BSONObj b=obj->normalise(input);

            cout<<"Normalised:"<<b.toString()<<endl;
            /*Pass the normalised object to rule engine*/
            list<string> m=r.match(b);
            list<string>::iterator i;
            /*Print results*/
            for(i=m.begin();i!=m.end();i++)
            {
            cout<<(*i)<<endl;
            }
            /*Increment index*/
            n++;
        }
        cout<<"N:"<<n<<endl;
    }
    return 0;
}
